/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.flexengine.time;

import com.flexengine.logger.Logger;
import java.util.*;

/**
 * @author Luann R. Athayde
 * @version 1.0
 * @since 1.0
 */
public class TimeManager implements Runnable {

    private static TimeManager            instance;
    private static final ArrayList<TimeManager> timers;
    static {
        instance = null;
        timers   = new ArrayList<>();
    }
    /**
     * 1 second = 1000 milis
     */
    public static final long MILI_SECOND =  1000L;
    /**
     * 1 second = 1000000000 nanos
     */
    public static final long NANO_SECOND =  1000000000L;
    /**
     * 1 Millisecond = 1000000 nanos
     */
    public static final long MILISECOND_IN_NANO = 1000000L;

    public static final long MIN_SLEEP_MILIS = 3L;
    public static final long MIN_SLEEP_NANOS = 3000000L;

    private Thread  tTime;
    private long    totalTime;
    private boolean counting;
    
    private boolean paused;
    
    private TimeManager() {
        this.totalTime = 0;
        this.tTime = null;
        this.counting = false;
        this.paused = false;
    }

    @Override
    public synchronized void run() {
        while(counting) {
            try {
                if( paused ) {
                    this.wait();
                }
                long timeBefore = milisTime();
                this.wait(1000);
                long diff = milisTime() - timeBefore;
                totalTime += diff;
            } catch(InterruptedException e) {
                Logger.logError(getClass().getSimpleName()+" - "+e);
                break;
            }
        }
        timers.remove(this);
    }
    
    public void reset() {
        this.totalTime = 0;
    }
    
    public synchronized void start() {
        if( counting ) {
            Logger.logWarning(getClass().getSimpleName()+" - start(): TimeManager is already running...");
            return;
        }
        totalTime = 0;
        counting = true;
        paused = false;
        tTime = new Thread(this, getClass().getSimpleName());
        timers.add(this);
        tTime.start();
    }
    
    public void stop() {
        counting = false;
        paused = false;
        if( tTime!=null ) {
            tTime.interrupt();
        }
        tTime = null;
        //timers.remove(this);
    }
    
    public synchronized void pause(boolean pause) {
        this.paused = pause;
        if( !paused ) {
            notify();
        }
    }

    public boolean isPaused() {
        return paused;
    }
    /**
     * Return the total time of the running engine in miliseconds...
     * @return totalTime
     */
    public long getTotalTime() {
        return totalTime;
    }

    public DateTime getTime() {
        DateTime retTime = new DateTime();
        retTime.setTime(totalTime);
        return retTime;
    }

    @Override
    public String toString() {
        return "TimeManager{" + "time=" + getTime() + ", paused=" + paused + '}';
    }
    
    public static long nanoTime()   {
        return System.nanoTime();
    }
    public static long milisTime()  {
        return System.currentTimeMillis();
    }

    public static long nanoToMilis(long nanos)    {
        return (nanos / MILISECOND_IN_NANO);
    }
    public static long miliToNanos(long milis)   {
        return milis * MILISECOND_IN_NANO;
    }
    
    public static Date getDate()    {
        return Calendar.getInstance().getTime();
    }

    public static ArrayList<TimeManager> getTimers() {
        return timers;
    }
    
    public static TimeManager getInstance() {
        if( instance==null ) {
            instance = new TimeManager();
        }
        return instance;
    }
    
    public static TimeManager newInstance() {
        TimeManager tm = new TimeManager();
        //timers.add(tm);
        return tm;
    }
    
}